<!--
 * @Author: 睡衣船长 121771372@qq.com
 * @Date: 2023-09-27 13:57:51
 * @LastEditors: 睡衣船长 121771372@qq.com
 * @LastEditTime: 2023-11-16 11:28:30
 * @Description:
-->
<script lang="ts" setup>
import { ref, nextTick, reactive } from "vue";
import { useRoute } from "vue-router";
import G6 from "@antv/g6";
import type {
  IShape,
  IGroup,
  ModelConfig,
  Item,
  INode,
  IEdge,
  G6GraphEvent,
} from "@antv/g6";
import {
  apiGetTemplateTaskFlowView,
  apiGetTaskRelyList,
  apiGetTaskFlowView,
} from "@/api/raiseShop/processLayout";
import processG6 from "./processG6";
import TaskDetail from "./TaskDetail/TaskDetail.vue";
import { _getImg, _msgBoxFun } from "@/utils";
import CreateTask from "./CreateTask.vue";
import {
  apiRemoveTemplateTask,
  apiRemoveTaskRely,
  apiSetTemplateTaskRely,
  apiCreateTaskStage,
  apiGetTaskStageList,
} from "@/api/raiseShop/task";
import UpdateTaskFloat from "./UpdateTaskFloat.vue";
import { apiGetStageList } from "@/api/raiseShop/stage";

/**
 * @name: 2712638312@qq.com
 * @desc: 默认赋值 props
 */
const props = withDefaults(
  defineProps<{
    searchInput?: string;
  }>(),
  {
    searchInput: "",
  }
);

const route = useRoute();

const { path, params } = route;

const isLoading = ref(true);

const viewRef = ref();

const viewer = ref();

const taskDetailRef = ref();

const taskSource = ref(params?.taskSource || 0);

const moduleId = ref("");

const viewerData: any = ref({
  nodes: [],
  edges: [],
});

const processRef = ref();

const _processG6 = new processG6();

G6.registerNode(
  "task-node",
  {
    draw: (cfg: any, group: any) => {
      return _processG6.createTaskNode(cfg, group);
    },
    afterDraw: (cfg: any, group: any) => {
      _processG6.afterDraw(cfg, group);
    },
    setState: (name: any, value: any, item: any) => {
      _processG6.setState(name, value, item);
    },
  },
  "rect"
);

G6.registerEdge("task-edge", {
  afterDraw: (cfg: any, group: any) => {
    _processG6.edgeAfterDraw(cfg, group);
  },
  draw: (cfg: any, group: any) => {
    return _processG6.edgeDraw(cfg, group);
  },
  setState: (name: any, value: any, item: any) => {
    _processG6.edgeSetState(name, value, item);
  },
});

G6.registerBehavior("drag-edge", {
  getEvents() {
    return {
      "edge:click": "onEdgeClick",
      "node:mouseup": "onNodeMouseUp",
      dragenter: "onDragEnter",
    };
  },
  onEdgeClick: async (ev: G6GraphEvent) => {
    const target = ev.target;
    const edge = ev.item as IEdge;
    if (
      target.cfg.name == "remove-edge-image1" ||
      target.cfg.name == "remove-edge-image2"
    ) {
      await apiRemoveTaskRely((edge._cfg && edge._cfg.id) || "");
      viewer.value.removeItem(edge);
      refreshTaskList();
    }
  },
  onNodeMouseUp: async (ev: G6GraphEvent) => {
    const node = ev.item;
    // const { x, y, width, height } = _pageCtrl.currentTargetNode?.getBBox() || { x: 0, y: 0, width: 0, height: 0 }
    // console.log(x, y, width, height, ev.x, ev.y)
    if (currentTargetNode.value) {
      const group = currentTargetNode.value.get("group");
      if (group.getShape(ev.x, ev.y)) {
        // console.log(node, 'node', _pageCtrl.currentTargetNode)
        const model1 = node.getModel();
        const model2 = currentTargetNode.value.getModel();
        console.log(model1.id, model2.id, "model2.id");
        // if (_pageCtrl.detail.value.tableStatus == 3 || (!_pageCtrl.isTemplate.value && !_pageCtrl.isManager)) {
        //   return
        // }
        if (model1.id != model2.id) {
          viewer.value.addItem("edge", {
            source: model1.id,
            target: model2.id,
          });
          try {
            await setRelyTask(model1.id || "", model2.id + "");
          } catch {
            //
          }
          refreshTaskList();
        }
      }
    }
  },
  onDragEnter: async (ev: G6GraphEvent) => {
    const node = ev.item;
    const type = node.getType();
    if (type == "node") {
      setCurrentTargetNode(node as INode);
    }
  },
});

const currentTargetNode = ref();

const updateTaskFloatRef = ref();

function setCurrentTargetNode(node: INode | undefined): void {
  currentTargetNode.value = node;
}

async function getTaskList() {
  console.log(params, "query", route);
  const taskParams: any = {
    taskSource: taskSource.value,
  };
  path.indexOf("template") > -1
    ? (taskParams.templateId = moduleId.value)
    : (taskParams.prepareStoreId = moduleId.value);

  // this.childTaskNumber.value = 0
  return path.indexOf("template") > -1
    ? await apiGetTemplateTaskFlowView(taskParams)
    : await apiGetTaskFlowView(taskParams);
}

async function getTaskRelyList() {
  const taskParams = {
    taskSource: taskSource.value,
    moduleId: moduleId.value,
  };
  return await apiGetTaskRelyList(taskParams);
}

G6.registerNode(
  "task-node",
  {
    draw: (cfg: any, group: any) => {
      return _processG6.createTaskNode(cfg, group);
    },
    afterDraw: (cfg: any, group: any) => {
      _processG6.afterDraw(cfg, group);
    },
    setState: (name: any, value: any, item: any) => {
      _processG6.setState(name, value, item);
    },
  },
  "rect"
);

G6.registerEdge("task-edge", {
  afterDraw: (cfg: any, group: any) => {
    _processG6.edgeAfterDraw(cfg, group);
  },
  draw: (cfg: any, group: any) => {
    return _processG6.edgeDraw(cfg, group);
  },
  setState: (name: any, value: any, item: any) => {
    _processG6.edgeSetState(name, value, item);
  },
});

G6.registerBehavior("drag-edge", {
  getEvents() {
    return {
      "edge:click": "onEdgeClick",
      "node:mouseup": "onNodeMouseUp",
      dragenter: "onDragEnter",
    };
  },
  onEdgeClick: async (ev: G6GraphEvent) => {
    const target = ev.target;
    const edge = ev.item as IEdge;
    if (
      target.cfg.name == "remove-edge-image1" ||
      target.cfg.name == "remove-edge-image2"
    ) {
      await apiRemoveTaskRely((edge._cfg && edge._cfg.id) || "");
      viewer.value.removeItem(edge);
      refreshTaskList();
    }
  },
  onNodeMouseUp: async (ev: G6GraphEvent) => {
    const node = ev.item;
    // const { x, y, width, height } = _pageCtrl.currentTargetNode?.getBBox() || { x: 0, y: 0, width: 0, height: 0 }
    // console.log(x, y, width, height, ev.x, ev.y)
    if (currentTargetNode.value) {
      const group = currentTargetNode.value.get("group");
      if (group.getShape(ev.x, ev.y)) {
        // console.log(node, 'node', _pageCtrl.currentTargetNode)
        const model1 = node.getModel();
        const model2 = currentTargetNode.value.getModel();
        console.log(model1.id, model2.id, "model2.id");
        // if (_pageCtrl.detail.value.tableStatus == 3 || (!_pageCtrl.isTemplate.value && !_pageCtrl.isManager)) {
        //   return
        // }
        if (model1.id != model2.id) {
          viewer.value.addItem("edge", {
            source: model1.id,
            target: model2.id,
          });
          try {
            await setRelyTask(model1.id || "", model2.id + "");
          } catch {
            //
          }
          refreshTaskList();
        }
      }
    }
  },
  onDragEnter: async (ev: G6GraphEvent) => {
    const node = ev.item;
    const type = node.getType();
    if (type == "node") {
      setCurrentTargetNode(node as INode);
    }
  },
});

const buildTaskViewer = async () => {
  isLoading.value = true;
  const res: any = await Promise.all([getTaskList(), getTaskRelyList()]);
  isLoading.value = false;
  console.log(res, "buildTaskViewer");
  viewerData.value.nodes.length = 0;
  viewerData.value.edges.length = 0;
  // this.lastLevel = -1
  // this.maxTaskRow = 0
  // this.taskIds.length = 0
  const ids: string[] = [];
  const stages: any = [];
  res[0].forEach((item: any) => {
    let row = 0;
    item.taskList.forEach((task: any) => {
      ids.push(task.id + "");
      // 判断阶段
      if (task.stage?.groupNum) {
        if (
          stages[task.stage.groupNum] &&
          stages[task.stage.groupNum].length > 0
        ) {
          stages[task.stage.groupNum].push(task.id);
        } else {
          stages[task.stage.groupNum] = [task.id];
        }
        task.stage.sortNum = stages[task.stage.groupNum].length;
      }
      viewerData.value.nodes.push({
        id: task.id + "",
        label: task.taskName + "",
        data: { ...task, level: item.level, row },
        layer: item.level > -1 ? item.level : 0,
      });
      row++;
      // if (item.level == 1) {
      //   this.taskIds.push(task.id + '')
      // }
    });
    // this.lastLevel++
    // if (item.taskList.length > this.maxTaskRow) {
    //   this.maxTaskRow = item.taskList.length
    // }
  });

  res[1].forEach((item: any) => {
    if (
      ids.indexOf(item.taskId + "") > -1 &&
      ids.indexOf(item.taskToId + "") > -1
    ) {
      viewerData.value.edges.push({
        id: item.id + "",
        source: item.taskId + "",
        target: item.taskToId + "",
      });
    }
  });
  // this.data.nodes.forEach((item: any) => {
  //   console.log(item.data.taskRelyId, 'taskRelyId')
  // })
};

nextTick(async () => {
  const width = processRef.value.clientWidth || 800;
  const height = (processRef.value.clientHeight || 500) - 5;

  _processG6.setIsTemplate(path.indexOf("template") > -1);

  taskSource.value = path.indexOf("template") > -1 ? taskSource.value : 1;

  moduleId.value =
    path.indexOf("template") > -1
      ? params?.templateId + ""
      : params?.shopManageId + "";

  viewer.value = new G6.Graph({
    container: viewRef.value, // String | HTMLElement，必须，在 Step 1 中创建的容器 id 或容器本身
    width, // Number，必须，图的宽度
    height, // Number，必须，图的高度
    groupByTypes: false,
    enabledStack: true,
    fitCenter: true,
    modes: {
      default: [
        "scroll-canvas",
        "drag-canvas",
        "drag-edge",
        {
          type: "create-edge",
          trigger: "drag",
        },
      ],
    },
    layout: {
      type: "dagre",
      rankdir: "LR",
      // align: 'UL',
      controlPoints: true,
      nodesepFunc: () => 1,
      ranksepFunc: () => 1,
      // type: 'dagre',
      // rankdir: 'LR',
      // controlPoints: true,
      // preventOverlap: true,
      nodeSize: [400, 220],
    },
    defaultNode: {
      size: path.indexOf("template") > -1 ? [298, 129] : [298, 159],
      type: "task-node",
    },
    defaultEdge: {
      type: "task-edge",
      // type: 'polyline',
      // size: 1,
      // color: '#409eff',
      // style: {
      //   endArrow: {
      //     path: 'M 0,0 L 8,4 L 8,-4 Z',
      //     fill: '#409eff'
      //   },
      //   radius: 20
      // }
    },
    // plugins: [minimap, toolbar, tooltip_taskType, tooltip_department, tooltip_executor, tooltip_time, contextMenu]
  });

  buildTaskViewer().then(() => {
    console.log(viewerData.value, "viewerData");
    viewer.value.data(viewerData.value);
    viewer.value.render();
  });

  // viewer.value.updateLayout({
  //   nodeOrder: _pageCtrl.taskIds
  // })

  // setTimeout(() => {
  //   const point = viewer.value.getViewPortCenterPoint()
  //   const graphWidth = viewer.value.getWidth()
  //   viewer.value.translate(point.x - graphWidth / 2, 0)
  //   reduceEdgePath()
  // }, 100)

  viewer.value.on("node:dblclick", async (ev: any) => {
    const node = ev.item;
    nowTaskId.value = node._cfg.id;
    // this.taskDetail.value = taskDetail
    nextTick(() => {
      // this._taskDetailDialogCtrl.showDialog(Number(node._cfg.id))
      taskDetailRef.value.show();
    });
  });

  _processG6.setFlowerNodeHover(viewer.value);
  setFlowerNodeClick();
});

const setFlowerNodeClick = () => {
  viewer.value.on("node:click", (ev: any) => {
    const node = ev.item;
    const bBox = ev?.target?.cfg?.canvasBBox;
    const model = node.getModel();
    if (ev?.target?.cfg?.name == "add-new-task-btn-yes") {
      console.log("add-new-task-btn-yes click");
      console.log(model, "model");
      fromTask.value = model.data;
      createTaskRef.value.show();
      viewer.value.setItemState(node, "selected", true);
      // const bBox = ev?.target?.cfg?.canvasBBox
      // this._createTaskCtrl.setPosition((bBox?.x + 50) + 'px', (bBox?.y - 28) + 'px')
      // this._createTaskCtrl.setHideFunc(() => {
      //   if (!node) return
      //   viewer.value.setItemState(node, 'create', false)
      //   viewer.value.setItemState(node, 'selected', false)
      //   this.reduceNodeWithEdge(node)
      // })
      // this._createTaskCtrl.setSaveFunc(async (res: taskModel) => {
      //   if (!node) return
      //   viewer.value.setItemState(node, 'create', false)
      //   viewer.value.setItemState(node, 'selected', false)
      //   this.refreshFlow(node)
      // })
      viewer.value.setItemState(node, "create", true);
    } else if (ev?.target?.cfg?.name == "task-del-icon") {
      _msgBoxFun({
        title: "删除",
        con: "是否删除此任务?",
        type: "error",
        confirmButtonText: "删除",
        customClass: "gapFlowMsgBox gapFlowMsgBoxDel",
        roundButton: true,
      }).then(async () => {
        // await this.removeTask(model.id)
        // useTaskStore().clearSubTaskDetail()
        // this.refreshFlow(node)+
        _processG6.isTemplate
          ? await apiRemoveTemplateTask({ ids: model.id })
          : {};
        refreshTaskList();
      });
    } else if (
      ["task-executor-department-icon", "task-department-name"].includes(
        ev?.target?.cfg?.name
      )
    ) {
      // if (!this.isManager) return
      nowTask.value = model?.data;
      console.log("点击部门", nowTask.value);
      if (nowTask.value.status == 3) return;
      // useUpdateTaskStore().getDepartmentList({ projectId: this.projectId, id: this.tableId })
      // updateTaskFloatRef.value.setData(this.isTemplate.value, nodeData.taskTypeId, nodeData.id)
      // updateTaskFloatRef.value.setChooseDepartment(nodeData.organizationId)
      updateTaskFloatRef.value.showDialog(
        "department",
        bBox?.x + "px",
        bBox?.y + 120 + "px"
      );
    } else if (
      ["task-executor-icon", "task-executor-name"].includes(
        ev?.target?.cfg?.name
      )
    ) {
      console.log("执行人");
      // if (!this.isManager) return
      // const nodeData = node.getModel()?.data
      // if (nodeData.status == 3) return
      // this.updateTaskFloatRef.value.setData(this.isTemplate.value, nodeData.taskTypeId, nodeData.id)
      // this.updateTaskFloatRef.value.setChooseDepartment(nodeData.organizationId)
      // this.updateTaskFloatRef.value.setChooseExecutor(nodeData.executor)
      // this.updateTaskFloatRef.value.showDialog('executor', (bBox?.x) + 'px', (bBox?.y + 60) + 'px', this.projectId, this.tableId)
    } else if (
      ["date-time-shape", "date-rect-shape"].includes(ev?.target?.cfg?.name)
    ) {
      // console.log('持续时长')
      // if (!this.isManager) return
      // const nodeData = node.getModel()?.data
      // if (nodeData.status == 3) return
      // this.updateTaskFloatRef.value.setData(this.isTemplate.value, nodeData.taskTypeId, nodeData.id)
      // if (this.isTemplate.value) {
      //   this.updateTaskFloatRef.value.setChooseTaskDay(nodeData.taskDay)
      //   this.updateTaskFloatRef.value.showDialog('time', (bBox?.x) + 'px', (bBox?.y + 60) + 'px')
      // }
      // else if (nodeData.taskType == 2) {
      //   this.updateTaskFloatRef.value.setChooseStartTime(nodeData.startTime)
      //   this.updateTaskFloatRef.value.showDialog('startTime', (bBox?.x + 50) + 'px', (bBox?.y - 28) + 'px')
      // }
    } else if (ev?.target?.cfg?.name == "task-sort") {
      console.log("编辑阶段");
      const nodeData = model?.data;
      openEditStageDialog(nodeData);
    } else {
      const nodes = viewer.value.getNodes();
      const isSelected = node.hasState("selected");
      if (!isSelected) {
        nodes.forEach((no: INode) => {
          no.setState("selected", false);
          _processG6.reduceNodeWithEdge(no, viewer.value);
        });
        node.setState("selected", true);
      } else {
        node.setState("selected", false);
      }
    }
    // const model = node.getModel() as TaskModelConfig
    if (model.data.taskType == 1) {
      _processG6.reduceNodeWithEdge(node, viewer.value);
    }
    // if (this.nowMilestoneId.value ? model.data.milestoneTaskType == 1 : model.data.taskType == 1) {
    //   this.reduceNodeWithEdge(node)
    // }
  });
};

/**
 * @author: 睡衣船长
 * @description: 重新处理画线逻辑，防止有重复
 * @return {*}
 */
const reduceEdgePath = () => {
  const nodes = viewer.value.getNodes();
  nodes.forEach((node: INode) => {
    const edges = node.getInEdges();
    // console.log(edges, 'edges')
    const startPoints: { x: number; y: number; i: number }[] = [];
    const reduceEdges: IEdge[] = [];
    edges.forEach((edge: IEdge, i: number) => {
      // console.log(edge.getModel(), 'getModel')
      const edgeStartPoint = edge.getModel().startPoint as {
        x: number;
        y: number;
        i: number;
      };
      if (edgeStartPoint) {
        startPoints.forEach((startPoint) => {
          if (startPoint.y == edgeStartPoint.y) {
            // console.log(startPoints, 'startPoints')
            reduceEdges.push(edges[i]);
            reduceEdges.push(edges[startPoint.i]);
          }
        });
        startPoints.push({ ...edgeStartPoint, i });
      }
    });
    if (reduceEdges.length > 0) {
      reduceEdges.forEach((edge) => {
        // console.log(edge, 'edge')
        const keyShape = edge && edge.get("keyShape");
        const model = edge.get("model");
        // console.log(keyShape, 'keyShape', model)
        const startPoint = model.startPoint || { x: 0, y: 0 };
        const endPoint = model.endPoint || { x: 0, y: 0 };
        if (startPoint.y < endPoint.y) {
          keyShape.attrs.path = [
            ["M", startPoint.x, startPoint.y],
            ["L", startPoint.x + 10, startPoint.y],
            [
              "C",
              startPoint.x + 15,
              startPoint.y,
              startPoint.x + 20,
              startPoint.y + 5,
              startPoint.x + 20,
              startPoint.y + 10,
            ],
            ["L", startPoint.x + 20, endPoint.y - 10],
            [
              "C",
              startPoint.x + 20,
              endPoint.y - 5,
              startPoint.x + 25,
              endPoint.y,
              startPoint.x + 30,
              endPoint.y,
            ],
            ["L", endPoint.x, endPoint.y],
          ];
        } else if (startPoint.y > endPoint.y) {
          keyShape.attrs.path = [
            ["M", startPoint.x, startPoint.y],
            ["L", startPoint.x + 10, startPoint.y],
            [
              "C",
              startPoint.x + 15,
              startPoint.y,
              startPoint.x + 20,
              startPoint.y - 5,
              startPoint.x + 20,
              startPoint.y - 10,
            ],
            ["L", startPoint.x + 20, endPoint.y + 10],
            [
              "C",
              startPoint.x + 20,
              endPoint.y + 5,
              startPoint.x + 25,
              endPoint.y,
              startPoint.x + 30,
              endPoint.y,
            ],
            ["L", endPoint.x, endPoint.y],
          ];
        }
      });
    }
  });
};

const nowTaskId = ref("");

const nowTask = ref();

const createTaskRef = ref();

const fromTask = ref();

const refreshTaskList = () => {
  buildTaskViewer().then(() => {
    console.log(viewerData.value, "viewerData refreshTaskList");
    viewer.value.data(viewerData.value);
    viewer.value.render();
  });
};

async function setRelyTask(taskId: Bus_StringNo, taskToId: Bus_StringNo) {
  _processG6.isTemplate
    ? await apiSetTemplateTaskRely({
        taskSource: taskSource.value,
        moduleId: moduleId.value,
        taskId,
        taskToId,
      })
    : {};
  refreshTaskList();
}

if (typeof window !== "undefined") {
  window.onresize = () => {
    if (!viewer.value || viewer.value.get("destroyed")) return;
    if (
      !processRef.value ||
      !processRef.value.clientWidth ||
      !processRef.value.clientHeight
    )
      return;
    viewer.value.changeSize(
      processRef.value.clientWidth,
      processRef.value.clientHeight - 5
    );
  };
}

// 编辑阶段
const editStageDialog = reactive({
  title: "编辑阶段",
  unScroll: false,
  checkCancel: true,
  showFooter: true,
  centerStyle: "padding:20px 20px;",
  contentStyle: "height:200px;width:500px;",
});

const editStageRef = ref();

const editStageDialogVisible = ref(false);

const editTaskDetail = ref();

const confirmEditStage = () => {
  const editParams: any = {
    taskId: editTaskDetail.value.id,
    moduleId: _processG6.isTemplate
      ? editTaskDetail.value.templateId
      : editTaskDetail.value.prepareStoreId,
    taskSource: taskSource.value,
  };
  const selectStage = stageList.value.find(
    (item) => item.stageName == stageName.value
  );
  if (selectStage) {
    editParams.stageId = selectStage.id;
  }
  apiCreateTaskStage(editParams).then(() => {
    editStageDialogVisible.value = false;
    refreshTaskList();
  });
};

const stageListRef = ref();

const getStageList = async () => {
  const res = await apiGetStageList({});
  stageList.value = res;
};

const openEditStageDialog = async (task: any) => {
  editTaskDetail.value = task;
  await getStageList();
  editStageDialogVisible.value = true;
  nextTick(() => {
    stageListRef.value.getOptionList();
  });
};

const stageList = ref([]);

const stageName = ref("");
</script>
<template>
  <div class="process-layout w-100 h-100" ref="processRef">
    <div class="loading flex" v-if="isLoading">加载中...</div>
    <div class="canvas" ref="viewRef"></div>
    <task-detail
      ref="taskDetailRef"
      :id="nowTaskId"
      :is-template="path.indexOf('template') > -1"
      @on-close="refreshTaskList"
    ></task-detail>
    <create-task
      :is-template="path.indexOf('template') > -1"
      :from-task="fromTask"
      ref="createTaskRef"
      @confirm-click="refreshTaskList"
    ></create-task>
    <update-task-float
      :task-detail="nowTask"
      ref="updateTaskFloatRef"
      :is-template="path.indexOf('template') > -1"
      @on-update="refreshTaskList"
    ></update-task-float>
    <xr-dialog
      ref="editStageRef"
      v-bind="editStageDialog"
      v-model="editStageDialogVisible"
      @confirm-click="confirmEditStage"
    >
      <template #body>
        <div style="color: #999; margin-bottom: 10px">
          请选择阶段，如果没有则输入阶段名称后，点击自动创建
        </div>
        <div class="flex w-100">
          <xr-select
            :select-props="{ allowCreate: true, filterable: true }"
            class="w-100"
            ref="stageListRef"
            :requestFun="stageList"
            placeholder="请选择阶段"
            select-label="stageName"
            select-value="stageName"
            v-model="stageName"
          ></xr-select>
        </div>
      </template>
    </xr-dialog>
  </div>
</template>
<style lang="scss" scoped>
.process-layout {
  background-color: #f0f2f5;
}

.loading {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  z-index: 999;
}
</style>
